package demo9

import "fmt"
// 代理设计模式
// 主要对象创建开销很大，或者某些操作需要安全控制，或者需要进程外的访问），直接访问会给使用者或者系统结构带来很多麻烦，我们可以在访问此对象时加上一个对此对象的访问层
//  场景比如：车票代售点，也能完成买卖车票。但是没有像车站的那么多功能，但是确实能够完成关键的功能，可以抽离出来业务逻辑中的关键层
// Subject RealSubject Proxy
// --------------------------------场景1-----------------------------------
// 官方案例来演示一下
// 原逻辑业务
type Subject interface{
	Do()
}

type RealSubject struct{}
func (RealSubject)Do(){
	fmt.Println("subject-------do")
}

// 代理
type Proxy struct{
	// 官方这里使用的指定的某个实例   | 这里可以指定某个抽象的类，比如 real Subject
	real RealSubject 
}

func (p Proxy)Do(){
	p.real.Do()
	fmt.Println("proxy------do")
}

// --------------------------------场景2-----------------------------------
// 需求：代理办证
// 需求分析：驾证办理需要体检，考试，学习，交钱等，代理办证：只需要交钱就可以获取到证件
// physical Examination study Pay     Pay

type payment interface{
	Pay()
}

type driverSchool struct{}

func (d driverSchool)Physical(){
	fmt.Println("体检....")
}
func (d driverSchool)Examination(){
	fmt.Println("考试....")
}
func (d driverSchool)Study(){
	fmt.Println("学习....")
}
func(d driverSchool)Pay(){
	fmt.Println("交钱....")
}

// 这里的作用只抽离整个复杂业务逻辑某个部分来执行，减少其他的开销
type agency struct{
	driver driverSchool
}

func (a agency)Pay(){
	fmt.Println("代理办证.....")
	a.driver.Pay()
	fmt.Println("办证完毕.....")
}


// --------------------------------场景2-----------------------------------

// 需求：缓存，
// 场景：当需要访问某模块数据较大的时候，这个时候需要不停的访问数据，那么这里可以考虑使用缓存代理来减少数据库的访问
// 这里适配器模式也能完成，但是适配器模式更倾向于两个实例之间的通信和连接以及两个接口之间的建立联系，
// 分析：比如到数据查询跟人的流水账, 每个人都有流水账而且比较多，访问次数也是较多的

type bill interface{
	Look()
}

type diary struct{
	name string
}

func NewDiary(name string) *diary{
	return &diary{
		name:name,
	}
}
func (d *diary)Look(){
	fmt.Println("流水账.....")
}

type ProxyDiary struct{
	d diary
	name string
}
func NewProxyDiary(d diary) *ProxyDiary{
	return &ProxyDiary{
		d:d,
		name:d.name,
	}
}

func (p ProxyDiary)Look(){
	// cache
	p.name += p.d.name + "今天的"
	fmt.Println(p.name ,"流水账.....")
}

// --------------------------------场景4-----------------------------------
// 真实场景
// 需求分析：连续多次的访问数据库，
// 需求：获取商品的Image
// DDD : 图片 Image  图片获取 ImageDownload | 

type Photographers interface{
	Download()
}

type Image struct{}
func NewImage() *Image{
	return &Image{}
}
func (Image)Download(){
	fmt.Println("图片下载......")
}

type ProxyImage struct{
	image Image
}
func (p *ProxyImage)Download(){
	if p.image == (Image{}){
		p.image = *NewImage()
		p.image.Download()
		return
	}
	fmt.Println("缓存下载")
}

// 总结： 关于代理模式，适配器模式，装饰器模式
// 装饰器模式：不修改原功能基础上增加额外的功能   | 包装 ===》把东西包装起来
// 适配器模式：对原来无法满足的功能变更现在满足的功能，这里不是同一个接口，两个接口	|	插头====》不同的插头插不同的插板（当插头满足不了插排需求，这里需要对插头进行适配）
// 代理模式： 对一个逻辑开销较大的服务业务体抽离出来关键的部分来使用，还是使用同一个接口，	|	代售====》代售票，代办证